解决Docker Machine中的容器文件不能持久的问题

目前Mac下使用docker的主流方式还是使用Docker machine.
Docker machine需要借用Virtual Box虚拟器启动一个Linux宿主机, 才能在上面启动多个Docker容器.

当我们在docker容器中运行服务时,经常会有需要将服务数据持久化的场景.比如运行Elasticsearch集群时, 需要将索引数据持久保存到磁盘.

那具体保存到哪里呢?容器的无状态特性决定了我们不应该将数据保存在容器中, 因为容器一旦重启, 文件数据就会丢失.一般应该使用volume参数,通过挂载外部文件系统到Docker容器中来保存数据.

当我在Mac下使用Docker开发时, 遇到这种场景, 自然就想到了将服务数据保存到Linux宿主机上. 结果很不辛, 使用Docker Machine创建的Linux宿主机的文件系统几乎也是不能持久的, Linux重启后, 之前写入的文件都会丢失.

不过好在使用Docker Machine创建的Linux宿主机上面,自动挂载了Mac上的用户目录到Linux宿主机上. 如下:

Linux: /Users   --->   Mac  : /Users

我们挂载文件系统时, 将应用的数据保存到/Users不久可以了吗?

然而现实还是那么残酷. 当我使用按照这个方式启动Elasticsearch时:

docker run -v "/Users/isaac/work/data":/usr/share/elasticsearch/data elasticsearch:2.3.3

却得到了以下错误:

Exception in thread "main" java.lang.IllegalStateException: Unable to access 'path.data' (/usr/share/elasticsearch/data/elasticsearch)
Likely root cause: java.nio.file.AccessDeniedException: /usr/share/elasticsearch/data/elasticsearch
    at sun.nio.fs.UnixException.translateToIOException(UnixException.java:84)
    at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
    at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
    at sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:384)
    at java.nio.file.Files.createDirectory(Files.java:674)
    at java.nio.file.Files.createAndCheckIsDirectory(Files.java:781)
    at java.nio.file.Files.createDirectories(Files.java:767)
    at org.elasticsearch.bootstrap.Security.ensureDirectoryExists(Security.java:337)
    at org.elasticsearch.bootstrap.Security.addPath(Security.java:314)
    at org.elasticsearch.bootstrap.Security.addFilePermissions(Security.java:259)
    at org.elasticsearch.bootstrap.Security.createPermissions(Security.java:212)
    at org.elasticsearch.bootstrap.Security.configure(Security.java:118)
    at org.elasticsearch.bootstrap.Bootstrap.setupSecurity(Bootstrap.java:196)
    at org.elasticsearch.bootstrap.Bootstrap.setup(Bootstrap.java:167)
    at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:270)
    at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:35)

经过分析, 文件操作失败是因为用户权限的问题.
查看Linux宿主机的用户信息:

docker-machine ssh default
cat /etc/passwd

得到以下内容:

root:x:0:0:root:/root:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/false
tc:x:1001:50:Linux User,,,:/home/tc:/bin/sh
docker:x:1000:50:Linux User,,,:/home/docker:/bin/sh

所以通过指定启动Docker容器的用户, 可以解决此问题:

docker run -u 1000 -v "/Users/isaac/work/data":/usr/share/elasticsearch/data elasticsearch:2.3.3 

其中:-u 1000 代表使用id为1000的docker用户来启动应用

在docker-compose.yml中指定启动用户为docker用户:

elasticsearch1:
    image: elasticsearch:2.3.3
    command: "elasticsearch -Des.cluster.name=elasticsearch -Des.discovery.zen.ping.unicast.hosts=elasticsearch_master"
    links:
      - elasticsearch_master
    volumes:
      - /Users/isaac/work/data:/usr/share/elasticsearch/data
    user: "1000"

ok,启动服务后, 数据终于持久不丢失了.


ybak
1.1k 声望96 粉丝

我喜欢5楼.-Weibo